package com.sikaryofficial.backend.manager;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sikaryofficial.backend.config.TenantFilterProperties;
import com.sikaryofficial.backend.constant.BlockTypeEnum;
import com.sikaryofficial.backend.constant.MyStatisticsTypeEnum;
import com.sikaryofficial.backend.constant.ProductStyleEnum;
import com.sikaryofficial.backend.constant.RedisCacheKey;
import com.sikaryofficial.backend.domain.dto.req.BrandTasteEvaluateListReq;
import com.sikaryofficial.backend.domain.dto.req.BrandTasteEvaluateOwnerReq;
import com.sikaryofficial.backend.domain.dto.req.BrandTasteEvaluateReq;
import com.sikaryofficial.backend.domain.dto.resp.BrandTasteEvaluateDTO;
import com.sikaryofficial.backend.domain.dto.resp.EvaluateTabTopData;
import com.sikaryofficial.backend.domain.dto.resp.IndexStatisticsOutputDTO;
import com.sikaryofficial.backend.domain.entity.BrandTaste;
import com.sikaryofficial.backend.domain.entity.BrandTasteEvaluate;
import com.sikaryofficial.backend.domain.entity.BrandTasteIndex;
import com.sikaryofficial.backend.domain.mapping.BrandTasteMapping;
import com.sikaryofficial.backend.domain.vo.CountryAreaVO;
import com.sikaryofficial.backend.domain.vo.EvaluateContentObj;
import com.sikaryofficial.backend.domain.vo.EvaluateReplyCount;
import com.sikaryofficial.backend.domain.vo.ObjectCount;
import com.sikaryofficial.backend.mapper.BrandTasteEvaluateMapper;
import com.sikaryofficial.backend.mapper.BrandTasteMapper;
import com.sikaryofficial.backend.service.IAttachmentService;
import com.sikaryofficial.backend.service.IBrandTasteEvaluateReplyService;
import com.sikaryofficial.backend.service.IBrandTasteEvaluateService;
import com.sikaryofficial.backend.service.IBrandTasteIndexService;
import com.sikaryofficial.backend.service.IBrandTasteService;
import com.sikaryofficial.backend.service.IMyStatisticsService;
import com.sikaryofficial.backend.service.IPointsDetailStrategy;
import com.sikaryofficial.backend.service.address.Ip2LocationService;
import com.sikaryofficial.backend.service.brand.cache.BrandTasteCacheService;
import com.sikaryofficial.backend.service.evaluate.EvaluateViewEvent;
import com.sikaryofficial.backend.service.evaluate.cache.BrandTasteIndexCacheService;
import com.sikaryofficial.backend.service.evaluate.cache.EvaluateCacheService;
import com.sikaryofficial.backend.service.statistics.MyStatisticsProcessor;
import com.sikaryofficial.backend.service.statistics.MyStatisticsEvent;
import com.sikaryofficial.backend.service.user.UserCacheService;
import com.sikaryofficial.backend.service.useraction.cache.UserActionCacheService;
import com.sikaryofficial.common.core.constant.EvaluateTypeEnum;
import com.sikaryofficial.common.core.constant.PointRuleConstant;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.utils.ip.IpUtils;
import com.sikaryofficial.common.redis.service.RedisService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.model.att.AttachmentResp;
import com.sikaryofficial.system.api.model.product.BrandTasteDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.compress.utils.Lists;
import org.bouncycastle.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.sikaryofficial.backend.constant.ProductConstant.*;
import static com.sikaryofficial.backend.utils.ProductUtil.buildProductMd5;

/**
 * @author : qinjinyuan
 * @desc : 口味评价管理服务
 * @date : 2023/10/30 15:39
 */
@Service
@Slf4j
public class BrandTasteEvaluateManager {

    private static final BigDecimal five = new BigDecimal(5);
    @Autowired
    private IBrandTasteEvaluateService evaluateService;
    @Autowired
    private IBrandTasteEvaluateReplyService replyService;
    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private IBrandTasteIndexService brandTasteIndexService;
    @Autowired
    private BrandTasteIndexCacheService brandTasteIndexCacheService;
    @Resource
    private Map<String, IPointsDetailStrategy> pointsDetailStrategyMap;
    @Autowired
    private BrandTasteCacheService brandTasteCacheService;
    @Autowired
    private IBrandTasteService brandTasteService;
    @Autowired
    private MyStatisticsProcessor myListener;
    @Autowired
    private UserCacheService userCacheService;
    @Resource(name = "asyncTaskExecutor")
    private ThreadPoolTaskExecutor executor;
    @Autowired
    private UserActionCacheService userActionCacheService;
    @Autowired
    private BrandTasteMapper brandTasteMapper;
    @Autowired
    private BrandTasteEvaluateMapper evaluateMapper;
    @Autowired
    private EvaluateCacheService evaluateCacheService;
    @Autowired
    private IMyStatisticsService myStatisticsService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TenantFilterProperties tenantFilterProperties;
    @Resource
    private ApplicationEventPublisher publisher;

    /**
     * 品牌指标统计
     *
     * @param brandTasteId
     * @return
     */
    public IndexStatisticsOutputDTO evaluateIndexStatistics(Long brandTasteId) {

        IndexStatisticsOutputDTO indexStatisticsOutputDTO = new IndexStatisticsOutputDTO();
        BrandTasteDTO brandTaste = brandTasteCacheService.getSignBrandTaste(brandTasteId);
        // 个人是否收藏，是否点赞
        if (Objects.nonNull(brandTaste)) {
            if (Objects.nonNull(brandTaste.getCollectionCount()) && brandTaste.getCollectionCount() > 0) {
                brandTaste.setHasOwnerCollection(userActionCacheService.getOwnerAction(SecurityUtils.getUserId(), brandTaste.getBrandTasteId(),
                        MyStatisticsTypeEnum.COLLECTION_PRODUCT_NUM.getBusinessType()));
            }
            if (Objects.nonNull(brandTaste.getLikesCount()) && brandTaste.getLikesCount() > 0) {
                brandTaste.setHasOwnerLikes(userActionCacheService.getOwnerAction(SecurityUtils.getUserId(), brandTaste.getBrandTasteId(),
                        MyStatisticsTypeEnum.LIKES_PRODUCT_NUM.getBusinessType()));
            }
        }
        indexStatisticsOutputDTO.setBrandTaste(brandTaste);
        indexStatisticsOutputDTO.setIndexStatisticsList(brandTasteIndexCacheService.evaluateIndexStatistics(brandTasteId));

        return indexStatisticsOutputDTO;
    }

    /**
     * 评论页签-top5相关聚合查询
     * <p>
     * 多线程情况下 userId 获取不正确（TheadLoacl）,需要再入口的地方统一获取
     *
     * @param style
     * @return
     */
    public EvaluateTabTopData topByStyle(String style) {
        EvaluateTabTopData result = new EvaluateTabTopData();
        // 下面的3个请求，采用java Commpletable异步请求，避免阻塞
        // 1、评价最多的型号，7条
        CompletableFuture<List<BrandTasteEvaluateDTO>> top7Brand =
                CompletableFuture.supplyAsync(() -> getBrandTasteByStyle(style, 7), executor)
                        .whenComplete((value, error) -> {
                            if (error != null) {
                                // 处理异常情况
                                log.error(TOP7_BRAND + " 调用失败：" + error.getMessage());
                            }
                            // 如果没有异常，则设置结果
                            result.setTop7Brand(value);
                        });

        CompletableFuture<List<BrandTasteEvaluateDTO>> latest =
                CompletableFuture.supplyAsync(() -> getLatestEvaluateByStyle(style, 7), executor)
                        .whenComplete((value, error) -> {
                            if (error != null) {
                                // 处理异常情况
                                log.error(LATEST_EVALUATE + " 调用失败：" + error.getMessage());
                            }
                            // 如果没有异常，则设置结果
                            result.setLatestEvaluate(value);
                        });

        CompletableFuture<List<BrandTasteEvaluateDTO>> mostViews =
                CompletableFuture.supplyAsync(() -> getMostViewsByStyle(style, 4), executor)
                        .whenComplete((value, error) -> {
                            if (error != null) {
                                // 处理异常情况
                                log.error(MOST_VIEWS + " 调用失败：" + error.getMessage());
                            }
                            // 如果没有异常，则设置结果
                            result.setMostViews(value);
                        });

        // 最后获取结构
        CompletableFuture.allOf(top7Brand, latest, mostViews).join();
        return result;
    }

    /**
     * 多租户查询最新评价
     *
     * @return
     */
    public List<BrandTasteEvaluateDTO> latestList() {
        return getLatestEvaluateByStyle(null, 7);
    }

    public List<BrandTasteEvaluateDTO> getLatestEvaluateByStyle(String style, int limitNum) {
        Long userId = SecurityUtils.getUserId();
        // 查询最新评价
        List<BrandTasteEvaluateDTO> result = evaluateCacheService.getLatestEvaluateByStyle(style, limitNum);
        // 通过缓存补充产品信息
        buildProductInfo(result);
        // 构建点赞数据
        buildLikesData(userId, result);
        // 填充头像数据
        Map<Long, String> userAvatarMap = userCacheService.getMultiUserAvatar(result.stream().map(BrandTasteEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        // 填充昵称
        Map<Long, String> userNickNameMap = userCacheService.getMultiUserNickName(result.stream().map(BrandTasteEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        result.forEach(item -> {
            item.setAvatar(MapUtils.getString(userAvatarMap, item.getCreatedBy(), ""));
            item.setNickName(MapUtils.getString(userNickNameMap, item.getCreatedBy(), ""));
        });
        return result;
    }

    public List<BrandTasteEvaluateDTO> getMostViewsByStyle(String style, int limitNum) {
        Long userId = SecurityUtils.getUserId();
        // 查询最新评价
        List<BrandTasteEvaluateDTO> result = evaluateCacheService.getMostViewsByStyle(style, limitNum);
        // 通过缓存补充产品信息
        buildProductInfo(result);
        // 构建点赞数据
        buildLikesData(userId, result);
        // 填充头像数据
        Map<Long, String> userAvatarMap = userCacheService.getMultiUserAvatar(result.stream().map(BrandTasteEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        // 填充昵称
        Map<Long, String> userNickNameMap = userCacheService.getMultiUserNickName(result.stream().map(BrandTasteEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        result.forEach(item -> {
            item.setAvatar(MapUtils.getString(userAvatarMap, item.getCreatedBy(), ""));
            item.setNickName(MapUtils.getString(userNickNameMap, item.getCreatedBy(), ""));
        });
        return result;
    }

    public List<BrandTasteEvaluateDTO> getBrandTasteByStyle(String style, int limitNum) {
        Long userId = SecurityUtils.getUserId();
        // 查询最新评价
        List<BrandTasteEvaluateDTO> result = evaluateCacheService.getProductByStyle(style, limitNum);
        // 通过缓存补充产品信息
        buildProductInfo(result);
        // 点赞统计及个人点赞数据
        buildEvaluateLikesData(userId, result);
        return result;
    }

    public BrandTasteEvaluateDTO detail(Long evaluateId) {
        if (Objects.isNull(evaluateId) || Objects.equals(evaluateId, 0L)) {
            throw new ServiceException("evaluateId is empty.");
        }
        // 1、详情查询
        BrandTasteEvaluateDTO result = evaluateService.detail(evaluateId);
        if (Objects.isNull(result)) {
            throw new ServiceException("evaluateId is empty.");
        }
        if (BlockTypeEnum.YES.getDbValue().equals(result.getHasBlocked())) {
            throw new ServiceException(" the evaluate had been blocked. ");
        }
        // 2、评价图像
        result.setAvatar(userCacheService.getSignUserAvatar(result.getCreatedBy()));
        result.setNickName(userCacheService.getSignUserNickName(result.getCreatedBy()));
        // 3、填充品牌相关字段
        buildBrandInfo(result);

        // 4、查阅量数据增加
        Integer tenantId = tenantFilterProperties.getTenantByBrand(SecurityUtils.getBrand());
        publisher.publishEvent(new EvaluateViewEvent(evaluateId, tenantId));
        return result;
    }

    private void buildBrandInfo(BrandTasteEvaluateDTO result) {
        BrandTasteDTO brandTaste = brandTasteCacheService.getSignBrandTaste(result.getBrandTasteId());
        if (Objects.nonNull(brandTaste)) {
            result.setModel(brandTaste.getModel());
            result.setStyle(brandTaste.getStyle());
            result.setBrandNo(brandTaste.getBrandNo());
            result.setTasteName(brandTaste.getTasteName());
            result.setProductName(brandTaste.getProductName());
            result.setCoverUrl(brandTaste.getCoverUrl());
        }
    }

    public IPage<BrandTasteEvaluateDTO> ownerList(BrandTasteEvaluateOwnerReq req) {
        if (Objects.nonNull(req.getUserId()) && req.getUserId() <= 0) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        Page<BrandTasteEvaluateDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        // 1、分页查询数据
        IPage<BrandTasteEvaluateDTO> evaluateDTOIPage = evaluateService.ownerList(customerPage, req);
        List<BrandTasteEvaluateDTO> brandTasteEvaluateDTOList = evaluateDTOIPage.getRecords();
        if (CollUtil.isEmpty(brandTasteEvaluateDTOList)) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        // 结果数据处理
        processEvaluateList(brandTasteEvaluateDTOList);
        return evaluateDTOIPage;
    }

    public IPage<BrandTasteEvaluateDTO> listPage(BrandTasteEvaluateListReq req) {
        if (Objects.nonNull(req.getBrandTasteId()) && req.getBrandTasteId() <= 0) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        Page<BrandTasteEvaluateDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        // 1、分页查询数据
        IPage<BrandTasteEvaluateDTO> evaluateDTOIPage = evaluateService.evaluateList(customerPage, req);
        List<BrandTasteEvaluateDTO> brandTasteEvaluateDTOList = evaluateDTOIPage.getRecords();
        if (CollUtil.isEmpty(brandTasteEvaluateDTOList)) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        // 结果数据处理
        processEvaluateList(brandTasteEvaluateDTOList);
        return evaluateDTOIPage;
    }

    private void processEvaluateList(List<BrandTasteEvaluateDTO> tasteEvaluateDTOS) {
        // 1、填充头像 & 替换地址
        // 填充头像数据
        Map<Long, String> userAvatarMap = userCacheService.getMultiUserAvatar(tasteEvaluateDTOS.stream().map(BrandTasteEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        // 填充昵称
        Map<Long, String> userNickNameMap = userCacheService.getMultiUserNickName(tasteEvaluateDTOS.stream().map(BrandTasteEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        tasteEvaluateDTOS.forEach(item -> {
            item.setAvatar(MapUtils.getString(userAvatarMap, item.getCreatedBy(), ""));
            item.setNickName(MapUtils.getString(userNickNameMap, item.getCreatedBy(), ""));
        });
        // 2、填充产品数据
        tasteEvaluateDTOS.forEach(this::buildBrandInfo);
        // 3、填充回复总数
        List<Long> evaluateIds = tasteEvaluateDTOS.stream().map(BrandTasteEvaluateDTO::getEvaluateId).collect(Collectors.toList());
        List<EvaluateReplyCount> evaluateReplyCountList = replyService.countByEvaluateId(evaluateIds);
        Map<Long, Integer> evaluateReplyCountMap = evaluateReplyCountList.stream().filter(item -> Objects.nonNull(item.getReplyCount()))
                .collect(Collectors.toMap(EvaluateReplyCount::getEvaluateId, EvaluateReplyCount::getReplyCount, (k1, k2) -> k1));
        tasteEvaluateDTOS.forEach(item -> item.setReplyCount(evaluateReplyCountMap.get(item.getEvaluateId())));

        // 4、填充点赞总数
        buildLikesData(SecurityUtils.getUserId(), tasteEvaluateDTOS);

        // 5、填充附件
        if (CollUtil.isNotEmpty(tasteEvaluateDTOS)) {
            Map<Long, List<AttachmentResp>> attachmentMap = attachmentService.getAttachmentByIds(evaluateIds);
            tasteEvaluateDTOS.forEach(item -> item.setAttachmentList(attachmentMap.get(item.getEvaluateId())));
        }
    }
    @Autowired
    private Ip2LocationService ip2LocationService;
    /**
     * 保存评价
     *
     * @param brandTasteEvaluate
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveEvaluate(BrandTasteEvaluateReq brandTasteEvaluate) {

        Long userId = SecurityUtils.getUserId();
        EvaluateTypeEnum evaluateTypeEnum = EvaluateTypeEnum.getNameByCode(brandTasteEvaluate.getEvaluateType());
        if (Objects.isNull(evaluateTypeEnum)) {
            throw new ServiceException("evaluate type is empty.");
        }

        if (Objects.isNull(userId)) {
            throw new ServiceException("user not login.");
        }
        // 1.1 如果brandTasteId不存在，则创建用户输入的产品
        createProduct(brandTasteEvaluate, evaluateTypeEnum);
        // 2、添加评价
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String ip = IpUtils.getIpAddr(request);
        CountryAreaVO countryAreaVO = ip2LocationService.getCountryAreaVO(ip);
        // 设置产品ID
        evaluateService.saveEvaluate(brandTasteEvaluate, ip, countryAreaVO);

        // 3、保存附件（图片）
        attachmentService.saveAttachmentList(brandTasteEvaluate.getEvaluateId(), brandTasteEvaluate.getAttachmentList(), userId);

        // 3.1 添加评价统计
        myListener.addMyStatistics(new MyStatisticsEvent(MyStatisticsTypeEnum.COMMENTS_EVALUATE_NUM.getBusinessType(), userId, brandTasteEvaluate.getEvaluateId()));

        // 3.2 添加该产品对应的评论总数
        myListener.addMyStatistics(new MyStatisticsEvent(MyStatisticsTypeEnum.COMMENTS_PRODUCT_COUNT.getBusinessType(), userId, brandTasteEvaluate.getBrandTasteId()));

        // 4、保存产品指标数据，方便数据统计
        saveBrandTasteIndex(brandTasteEvaluate.getBrandTasteId(), brandTasteEvaluate.getEvaluateContent(), userId);
        // 自助评价
        IPointsDetailStrategy evaluateStrategy = pointsDetailStrategyMap.get(PointRuleConstant.EVALUATE+ IPointsDetailStrategy.SUFFIX);
        evaluateStrategy.updatePointsByInputValue(brandTasteEvaluate.getEvaluateId(), userId, 0, brandTasteEvaluate.getP(), "");
        // 扫描评价积分-100分获取
        IPointsDetailStrategy scanCodeStrategy = pointsDetailStrategyMap.get(PointRuleConstant.SCAN_CODE+ IPointsDetailStrategy.SUFFIX);
        scanCodeStrategy.updatePointsByInputValue(brandTasteEvaluate.getEvaluateId(), userId, 0, brandTasteEvaluate.getP(), "");
        // 8、清除下评价统计缓存
        redisService.deleteObject(MessageFormat.format(RedisCacheKey.BRAND_TASTE_INDEX_STATISTICS_CACHE, brandTasteEvaluate.getBrandTasteId()));
        // 7、添加完积分后续处理-发送综合评分计算处理消息
        CompletableFuture.runAsync(() -> computeScoreForProduct(brandTasteEvaluate.getBrandTasteId()));
        return true;
    }

    public void computeScoreForProduct(Long brandTasteId) {
        if (Objects.isNull(brandTasteId)) {
            log.warn("computeScoreForProduct==the product brandTasteId is null");
            return;
        }
        /**
         * 1、根据ID查询数据存在性：updateTime
         * 2、时间差比较，大于10分钟，则进行数据更新
         * 3、查询当前产品对应评价的总和评分，并更新数据
         * 4、同步更新缓存数据
         */
        BrandTaste brandTaste = brandTasteMapper.selectOne(new LambdaQueryWrapper<BrandTaste>()
                .select(BrandTaste::getUpdatedTime, BrandTaste::getBrandTasteId)
                .eq(BrandTaste::getBrandTasteId, brandTasteId)
                .eq(BrandTaste::getDeletedVersion, 0)
        );
        if (Objects.isNull(brandTaste)) {
            log.warn("computeScoreForProduct=====the product info is empty");
            return;
        }
        // 计算综合评分数据
        BrandTasteEvaluate evaluate = evaluateMapper.getAvgScoreByProductId(brandTasteId);
        // 更新综合评分数据
        BigDecimal compositeScore = Objects.isNull(evaluate) ? five : evaluate.getCompositeScore();
        brandTaste.setUpdatedTime(new Date());
        brandTaste.setCompositeScore(compositeScore);
        brandTasteMapper.updateById(brandTaste);
        // 更新综合评分缓存数据
        BrandTasteDTO brandTasteDTO = brandTasteCacheService.getSignBrandTaste(brandTasteId);
        if (Objects.nonNull(brandTasteDTO)) {
            brandTasteDTO.setCompositeScore(compositeScore);
            brandTasteCacheService.updateBrandTasteCacheOnly(brandTasteDTO);
        }
        // 对最新的店铺缓存进行清理
        Collection<String> keys = redisService.keys(RedisCacheKey.LATEST_EVALUATE_STYLE_CACHE + "*");
        for (String key : keys) {
            redisService.deleteObject(key);
        }
    }

    /**
     * 1.1 如果brandTasteId不存在，则创建用户输入的产品
     *
     * @param brandTasteEvaluate
     */
    private void createProduct(BrandTasteEvaluateReq brandTasteEvaluate, EvaluateTypeEnum evaluateTypeEnum) {
        // 只有自助评价才可能产生新的产品 （产品ID不为空也不进行处理）
        if (evaluateTypeEnum.equals(EvaluateTypeEnum.SCAN_CODE) || Objects.nonNull(brandTasteEvaluate.getBrandTasteId())) {
            return;
        }
        // 1.1 、如果brandTasteId不存在，则创建用户输入的产品
        ProductStyleEnum styleEnum = ProductStyleEnum.getByCode(brandTasteEvaluate.getStyle());
        if (Objects.isNull(styleEnum)) {
            throw new ServiceException("the product style is empty.");
        }
        String style = styleEnum.getCode();
        String md5 = buildProductMd5(brandTasteEvaluate.getBrandNo(), brandTasteEvaluate.getModel(), style, brandTasteEvaluate.getTasteName());
        // 如果评价的产品已经存在
        BrandTaste brandTaste = brandTasteService.getOne(new LambdaQueryWrapper<BrandTaste>()
                .eq(BrandTaste::getMd5, md5)
                .eq(BrandTaste::getDeletedVersion, 0L)
                .last(" limit 1")
        );
        if (Objects.nonNull(brandTaste)) {
            // 设置产品ID
            brandTasteEvaluate.setBrandTasteId(brandTaste.getBrandTasteId());
            return;
        }
        // 如果评价的产品不存在
        Long brandTasteId = IdWorker.getId();
        brandTaste = BrandTaste.builder()
                .createdName(SecurityUtils.getUsername())
                .createdBy(SecurityUtils.getUserId())
                .createdTime(new Date())
                .brandTasteId(brandTasteId)
                .productName(brandTasteEvaluate.getProductName())
                .tasteName(brandTasteEvaluate.getTasteName())
                .brandNo(brandTasteEvaluate.getBrandNo())
                .model(brandTasteEvaluate.getModel())
                .style(style)
                .source(SOURCE_USER_EVALUATE)
                .md5(buildProductMd5(brandTasteEvaluate.getBrandNo(), brandTasteEvaluate.getModel(), style, brandTasteEvaluate.getTasteName()))
                .build();
        // 设置评价第1张图片为产品封面
        if (CollUtil.isNotEmpty(brandTasteEvaluate.getAttachmentList())) {
            AttachmentResp attachmentResp = brandTasteEvaluate.getAttachmentList().stream().findFirst().orElse(null);
            if (Objects.nonNull(attachmentResp)) {
                brandTaste.setCoverUrl(attachmentResp.getUrl());
            }
        }
        // 更新缓存数据
        brandTasteCacheService.updateBrandTasteCache(BrandTasteMapping.INSTANCE.coverToDTO(brandTaste));
        brandTasteService.save(brandTaste);
        // 设置产品ID
        brandTasteEvaluate.setBrandTasteId(brandTasteId);
    }

    /**
     * 口味指标数据存储
     *
     * @param evaluateContentObs 评论指标内容
     * @param userId             用户ID
     */
    private void saveBrandTasteIndex(Long brandTasteId, List<EvaluateContentObj> evaluateContentObs, Long userId) {
        if (CollUtil.isEmpty(evaluateContentObs)) {
            log.error("saveBrandTasteIndex param is empty.");
            return;
        }
        if (Objects.isNull(userId) || Objects.equals(userId, 0L)) {
            log.warn("user is no login.");
            return;
        }
        List<BrandTasteIndex> brandTasteIndexList = Lists.newArrayList();
        for (EvaluateContentObj attendReq : evaluateContentObs) {
            String label = attendReq.getLabel();
            BrandTasteIndex tasteIndex = BrandTasteIndex.builder().evaluateIndexId(IdWorker.getId())
                    .brandTasteId(brandTasteId)
                    .label(label)
                    .add(attendReq.getAdd()).reduce(attendReq.getReduce()).justRight(attendReq.getJustRight())
                    .createdBy(userId).createdTime(new Date()).build();
            brandTasteIndexList.add(tasteIndex);
        }
        brandTasteIndexService.saveBatch(brandTasteIndexList);
    }

    /**
     * 更新评价
     *
     * @param brandTasteEvaluate
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateEvaluate(BrandTasteEvaluateReq brandTasteEvaluate) {
        if (Objects.isNull(brandTasteEvaluate)) {
            log.error("updateEvaluate param is empty.");
            return false;
        }
        return evaluateService.updateEvaluate(brandTasteEvaluate);
    }

    /**
     * 删除评价
     *
     * @param evaluateIds
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean removeEvaluate(Long[] evaluateIds) {
        if (Arrays.isNullOrEmpty(evaluateIds)) {
            log.error("removeEvaluate param is empty.");
            return false;
        }
        // 删除评论
        evaluateService.removeEvaluate(evaluateIds);
        // 删除跟评
        replyService.removeReply(evaluateIds);

        return evaluateService.removeEvaluate(evaluateIds);
    }

    /**
     * 构建评价的点赞统计及个人点赞数据
     *
     * @param result
     */
    public void buildLikesData(Long userId, List<BrandTasteEvaluateDTO> result) {
        if (CollUtil.isEmpty(result)) {
            return;
        }
        Optional.of(result).ifPresent(list -> {
            // 点赞数量填充
            List<ObjectCount> objectCountList = myStatisticsService.countByObjectIds(list.stream().map(BrandTasteEvaluateDTO::getEvaluateId).collect(Collectors.toList()));
            Map<Long, List<ObjectCount>> objectCountMap = objectCountList.stream().collect(Collectors.groupingBy(ObjectCount::getObjectId));
            result.forEach(replyDTO -> {
                List<ObjectCount> objectCounts = MapUtils.getObject(objectCountMap, replyDTO.getEvaluateId());
                if (CollUtil.isEmpty(objectCounts)) {
                    return;
                }
                objectCounts.stream().filter(e -> MyStatisticsTypeEnum.LIKES_PRODUCT_EVALUATE_NUM.getBusinessType().equals(e.getBusinessType())).findFirst().ifPresent(e -> {
                    replyDTO.setLikesCount(e.getObjectCount());
                });
            });
        });
        // 是否有我的点赞
        result.forEach(evaluateDTO -> {
            if (Objects.nonNull(evaluateDTO.getLikesCount()) && evaluateDTO.getLikesCount() > 0) {
                evaluateDTO.setHasOwnerLikes(userActionCacheService.getOwnerAction(userId, evaluateDTO.getEvaluateId(),
                        MyStatisticsTypeEnum.LIKES_PRODUCT_EVALUATE_NUM.getBusinessType()));
            }
        });
    }

    /**
     * 填充产品信息
     *
     * @param result
     */
    private void buildProductInfo(List<BrandTasteEvaluateDTO> result) {
        if (CollUtil.isEmpty(result)) {
            return;
        }
        Set<Long> brandTasteIdSet = result.stream().map(BrandTasteEvaluateDTO::getBrandTasteId).collect(Collectors.toSet());
        List<BrandTasteDTO> brandTasteDTOList = brandTasteCacheService.getBrandTasteList(new ArrayList<>(brandTasteIdSet));
        if (CollUtil.isEmpty(brandTasteDTOList)) {
            return;
        }
        Map<Long, BrandTasteDTO> brandTasteDTOMap =
                brandTasteDTOList.stream().collect(Collectors.toMap(BrandTasteDTO::getBrandTasteId, Function.identity(), (k1, k2) -> k1));
        result.forEach(item -> {
            BrandTasteDTO cacheBrandTasteDTO = MapUtils.getObject(brandTasteDTOMap, item.getBrandTasteId());
            if (Objects.isNull(cacheBrandTasteDTO)) {
                return;
            }
            item.setBrandNo(cacheBrandTasteDTO.getBrandNo());
            item.setModel(cacheBrandTasteDTO.getModel());
            item.setTasteName(cacheBrandTasteDTO.getTasteName());
            item.setStyle(cacheBrandTasteDTO.getStyle());
            item.setCoverUrl(cacheBrandTasteDTO.getCoverUrl());
            item.setProductName(cacheBrandTasteDTO.getProductName());
            item.setCompositeScore(cacheBrandTasteDTO.getCompositeScore());
        });
    }

    /**
     * 构建评价的点赞统计及个人点赞数据
     *
     * @param result
     * @return
     */
    private void buildEvaluateLikesData(Long userId, List<BrandTasteEvaluateDTO> result) {
        if (CollUtil.isEmpty(result)) {
            return;
        }
        // 填充每条跟评对应的点赞数量
        result.forEach(item -> {
            BrandTasteDTO brandTasteDTO = brandTasteCacheService.getSignBrandTaste(item.getBrandTasteId());
            if (Objects.nonNull(brandTasteDTO) && Objects.nonNull(brandTasteDTO.getLikesCount())) {
                item.setLikesCount(brandTasteDTO.getLikesCount() >= 0 ? brandTasteDTO.getLikesCount() : 0);
            }
        });
        // 是否自己点赞
        result.forEach(item -> {
                    if (Objects.nonNull(item.getLikesCount()) && item.getLikesCount() > 0) {
                        item.setHasOwnerLikes(userActionCacheService.getOwnerAction(userId, item.getBrandTasteId(),
                                MyStatisticsTypeEnum.LIKES_PRODUCT_NUM.getBusinessType()));
                    }
                }
        );
    }


}
